package org.tlang.ast.list.statement;

import org.tlang.ast.AST;
import org.tlang.ast.ASTLeaf;
import org.tlang.ast.ASTList;
import org.tlang.ast.list.type.TypeTag;
import org.tlang.context.Location;
import org.tlang.context.SymbolTable;
import org.tlang.context.TypeTable;
import org.tlang.context.ValueTable;
import org.tlang.exception.TypeException;
import org.tlang.metaclass.TGetter;
import org.tlang.metaclass.TVar;
import org.tlang.type.Type;

import java.util.List;

public class VarDefineStatement extends ASTList {
    private int index;

    public VarDefineStatement(List<AST> children) {
        super(children);
        this.index = Location.UNKNOWN;
    }

    private String name() {
        return ((ASTLeaf) child(0)).token().getText();
    }

    private TypeTag typeTag() {
        return (TypeTag) child(1);
    }

    private AST expr() {
        if (numChildren() > 2) {
            return child(numChildren() - 1);
        } else {
            return null;
        }
    }

    @Override
    public void lookup(SymbolTable symbolTable, TypeTable typeTable) {
        this.index = symbolTable.add(name());
        lookupInternal(symbolTable, typeTable);
    }

    public void lookupAsField(SymbolTable symbolTable, TypeTable typeTable) {
        this.index = symbolTable.put(name());
        lookupInternal(symbolTable, typeTable);
    }

    private void lookupInternal(SymbolTable symbolTable, TypeTable typeTable) {
        for (int i = 1; i < numChildren(); i++) {
            child(i).lookup(symbolTable, typeTable);
        }
        typeTable.put(index, typeTag().type(typeTable));
    }

    @Override
    public Type typeCheck(TypeTable typeTable) throws TypeException {
        Type tagType = typeTag().typeCheck(typeTable);
        typeTable.put(index, tagType);
        AST expr = expr();
        if (expr != null) {
            Type exprType = expr.typeCheck(typeTable);
            exprType.assertSubTypeOf(tagType, typeTable, this);
        }
        return tagType;
    }

    @Override
    public Object eval(ValueTable valueTable) {
        AST expr = expr();
        Object value = null;
        if (expr != null) {
            value = expr.eval(valueTable);
        }
        if (value instanceof TGetter) {
            value = ((TGetter) value).get();
        }
        valueTable.add(index, new TVar(value)); // 如果没有初始化表达式，默认初始化为null
        return name();
    }

    @Override
    public String toString() {
        return "( var " + name() + " " + typeTag() + " = " + expr() + " )";
    }
}
